use chrono::{DateTime, Local};
use log::{Level, Record};
use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use std::sync::Mutex;
use std::collections::HashMap;
use once_cell::sync::Lazy;

/// 日志文件管理器
/// 负责按日期创建和管理日志文件，支持多线程安全写入
static LOG_FILES: Lazy<Mutex<HashMap<String, BufWriter<File>>>> = Lazy::new(|| {
    Mutex::new(HashMap::new())
});

/// 自定义日志记录器
/// 实现按日期分文件存储，包含线程名、时间戳、日志级别等信息
pub struct FileLogger {
    log_dir: PathBuf,
}

impl FileLogger {
    /// 创建新的文件日志记录器
    /// 
    /// # 参数
    /// * `log_dir` - 日志文件存储目录
    /// 
    /// # 返回值
    /// * `Result<Self, String>` - 成功返回日志记录器实例，失败返回错误信息
    pub fn new(log_dir: PathBuf) -> Result<Self, String> {
        // 确保日志目录存在
        if !log_dir.exists() {
            std::fs::create_dir_all(&log_dir)
                .map_err(|e| format!("创建日志目录失败: {}", e))?;
        }
        
        Ok(FileLogger { log_dir })
    }
    
    /// 获取当前日期的日志文件路径
    /// 
    /// # 返回值
    /// * `PathBuf` - 日志文件路径，格式为: logs/YYYY-MM-DD.log
    fn get_log_file_path(&self) -> PathBuf {
        let now = Local::now();
        let date_str = now.format("%Y-%m-%d").to_string();
        self.log_dir.join(format!("{}.log", date_str))
    }
    
    /// 获取或创建日志文件的写入器
    /// 
    /// # 参数
    /// * `file_path` - 日志文件路径
    /// 
    /// # 返回值
    /// * `Result<(), String>` - 成功返回空，失败返回错误信息
    fn ensure_log_file(&self, file_path: &PathBuf) -> Result<(), String> {
        let path_str = file_path.to_string_lossy().to_string();
        let mut files = LOG_FILES.lock().map_err(|e| format!("获取日志文件锁失败: {}", e))?;
        
        if !files.contains_key(&path_str) {
            let file = OpenOptions::new()
                .create(true)
                .append(true)
                .open(file_path)
                .map_err(|e| format!("打开日志文件失败: {}", e))?;
            
            let writer = BufWriter::new(file);
            files.insert(path_str, writer);
        }
        
        Ok(())
    }
    
    /// 写入日志记录
    /// 同时输出到文件和控制台
    /// 
    /// # 参数
    /// * `record` - 日志记录
    /// 
    /// # 返回值
    /// * `Result<(), String>` - 成功返回空，失败返回错误信息
    pub fn log(&self, record: &Record) -> Result<(), String> {
        let file_path = self.get_log_file_path();
        self.ensure_log_file(&file_path)?;
        
        let now: DateTime<Local> = Local::now();
        let thread_name = std::thread::current()
            .name()
            .unwrap_or("unnamed")
            .to_string();
        
        // 格式化日志消息: [时间] [线程名] [级别] [模块] 消息
        let log_message = format!(
            "[{}] [{}] [{}] [{}] {}\n",
            now.format("%Y-%m-%d %H:%M:%S%.3f"),
            thread_name,
            record.level(),
            record.module_path().unwrap_or("unknown"),
            record.args()
        );
        
        // 输出到控制台
        print!("{}", log_message);
        
        // 输出到文件
        let path_str = file_path.to_string_lossy().to_string();
        let mut files = LOG_FILES.lock().map_err(|e| format!("获取日志文件锁失败: {}", e))?;
        
        if let Some(writer) = files.get_mut(&path_str) {
            writer.write_all(log_message.as_bytes())
                .map_err(|e| format!("写入日志失败: {}", e))?;
            writer.flush()
                .map_err(|e| format!("刷新日志缓冲区失败: {}", e))?;
        }
        
        Ok(())
    }
}

impl log::Log for FileLogger {
    /// 检查是否启用指定级别的日志
    /// 
    /// # 参数
    /// * `metadata` - 日志元数据
    /// 
    /// # 返回值
    /// * `bool` - 是否启用该级别的日志
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= Level::Debug
    }
    
    /// 记录日志
    /// 
    /// # 参数
    /// * `record` - 日志记录
    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            if let Err(e) = self.log(record) {
                eprintln!("日志写入失败: {}", e);
            }
        }
    }
    
    /// 刷新日志缓冲区
    fn flush(&self) {
        if let Ok(mut files) = LOG_FILES.lock() {
            for writer in files.values_mut() {
                let _ = writer.flush();
            }
        }
    }
}

/// 获取日志目录路径
/// 在开发环境下使用项目目录，生产环境下使用系统配置目录
/// 
/// # 返回值
/// * `Result<PathBuf, String>` - 成功返回日志目录路径，失败返回错误信息
fn get_log_directory() -> Result<PathBuf, String> {
    // 检查是否为开发环境
    let is_dev = cfg!(debug_assertions) || std::env::var("TAURI_DEV").is_ok();
    
    if is_dev {
        // 开发环境：使用项目目录下的out/logs文件夹
        let current_dir = std::env::current_dir()
            .map_err(|e| format!("无法获取当前目录: {}", e))?;
        Ok(current_dir.join("out").join("logs"))
    } else {
        // 生产环境：使用系统配置目录
        let log_dir = dirs::config_dir()
            .ok_or("无法获取配置目录")?
            .join("e-shortcuts")
            .join("logs");
        Ok(log_dir)
    }
}

/// 初始化日志系统
/// 设置日志级别和输出格式，同时输出到控制台和文件
/// 在开发环境下使用项目目录，生产环境下使用系统配置目录
/// 
/// # 返回值
/// * `Result<(), String>` - 成功返回空，失败返回错误信息
pub fn init_logger() -> Result<(), String> {
    // 获取日志目录路径
    let log_dir = get_log_directory()?;
    
    // 创建文件日志记录器
    let file_logger = FileLogger::new(log_dir)?;
    
    // 设置日志记录器
    log::set_boxed_logger(Box::new(file_logger))
        .map_err(|e| format!("设置日志记录器失败: {}", e))?;
    
    // 设置日志级别
    log::set_max_level(log::LevelFilter::Debug);
    
    log::info!("日志系统初始化完成");
    Ok(())
}

/// 清理旧日志文件
/// 删除超过指定天数的日志文件
/// 
/// # 参数
/// * `days` - 保留天数
/// 
/// # 返回值
/// * `Result<(), String>` - 成功返回空，失败返回错误信息
pub fn cleanup_old_logs(days: u64) -> Result<(), String> {
    let log_dir = dirs::config_dir()
        .ok_or("无法获取配置目录")?
        .join("e-shortcuts")
        .join("logs");
    
    if !log_dir.exists() {
        return Ok(());
    }
    
    let cutoff_time = Local::now() - chrono::Duration::days(days as i64);
    
    for entry in std::fs::read_dir(&log_dir)
        .map_err(|e| format!("读取日志目录失败: {}", e))? {
        let entry = entry.map_err(|e| format!("读取目录项失败: {}", e))?;
        let path = entry.path();
        
        if path.is_file() && path.extension().map_or(false, |ext| ext == "log") {
            if let Ok(metadata) = entry.metadata() {
                if let Ok(modified) = metadata.modified() {
                    let modified_time: DateTime<Local> = modified.into();
                    if modified_time < cutoff_time {
                        if let Err(e) = std::fs::remove_file(&path) {
                            log::warn!("删除旧日志文件失败 {}: {}", path.display(), e);
                        } else {
                            log::info!("已删除旧日志文件: {}", path.display());
                        }
                    }
                }
            }
        }
    }
    
    Ok(())
}